package com.ls.shiroWithJwt.shiro;

import com.ls.shiroWithJwt.constant.Constants;
import com.ls.shiroWithJwt.entity.UserEntity;
import com.ls.shiroWithJwt.shiro.token.JwtAuthenticationToken;
import com.ls.shiroWithJwt.utils.JwtUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component(value = "authRealm")
public class AuthRealm extends AuthorizingRealm {


    private static final Logger LOGGER = LoggerFactory.getLogger(AuthRealm.class);


    /**
     * 这里的hash值为JwtAuthenticationToken.getCredentials()的默认返回值的hash值，对应的hash算法在ShiroConfig配置，一定不要搞错！！！
     */
    private static final String DEFAULT_JWT_HASH = "d41d8cd98f00b204e9800998ecf8427e";

    public Class<?> getAuthenticationTokenClass() {
        return JwtAuthenticationToken.class;//此Realm只支持JwtToken
    }

    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        JwtAuthenticationToken jwtToken = (JwtAuthenticationToken) token;
        if(jwtToken.getJwt() == null || "".equals(jwtToken.getJwt().trim()))
            return validateUserNameAndPwd(jwtToken);
        try {
            Map<String, String> claims = JwtUtil.verifyToken(jwtToken.getJwt());
            String userName = claims.get(Constants.DEFAULT_PRINCIPAL);

            if(userName == null || !"admin".equals(userName.trim())){
                throw new AuthenticationException("不存在的用户名");
            }

            //这里改为自己的代码，根据用户名获取用户数据,begin
            //模拟获取用户数据过程
            if(!jwtToken.getUserName().equals("admin")){
                throw new AuthenticationException("不存在的用户名");
            }
            UserEntity userEntity = new UserEntity();
            userEntity.setAge(26);
            userEntity.setId(1l);
            userEntity.setRealName("管理员");
            userEntity.setUserName("admin");
            //这里改为自己的代码，根据用户名获取用户数据,end

            return new SimpleAuthenticationInfo(userEntity, DEFAULT_JWT_HASH,null,getName());
        } catch (Exception e) {
            throw new AuthenticationException("token认证失败");
        }

    }

    /**
     * 验证用户名密码
     * @param jwtToken
     * @return
     */
    private AuthenticationInfo validateUserNameAndPwd(JwtAuthenticationToken jwtToken) {
        if(jwtToken.getUserName() == null || "".equals(jwtToken.getUserName().trim())
                || jwtToken.getPassword() == null || "".equals(jwtToken.getPassword().trim())){
            throw new AuthenticationException("用户名或密码为空");
        }

        //这里改为自己的代码，根据用户名获取用户数据,begin
        //模拟获取用户数据过程
        if(!jwtToken.getUserName().equals("admin")){
            throw new AuthenticationException("不存在的用户名");
        }
        UserEntity userEntity = new UserEntity();
        userEntity.setAge(26);
        userEntity.setId(1l);
        userEntity.setRealName("管理员");
        userEntity.setUserName("admin");
        String passwordHash = "e10adc3949ba59abbe56e057f20f883e";//这里的passwordHash一般为从数据库取出来的用户密码的hash值
        //这里验证用户密码
        return new SimpleAuthenticationInfo(userEntity,passwordHash,null,getName());
        //这里改为自己的代码，根据用户名获取用户数据,end

    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.该数据在ShiroConfig做了缓存配置，目前使用的是保存在redis中策略
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        UserEntity userEntity = (UserEntity) principals.getPrimaryPrincipal();
        //此处编写自己的的逻辑，根据用户获取对应角色和权限信息begin
        info.addRole("admin");
        info.addStringPermission("sys:test1");
        //此处编写自己的的逻辑，根据用户获取对应角色和权限信息end
        return info;
    }

    public AuthorizationInfo getAuthorizationInfo(Subject subject){
        return this.getAuthorizationInfo(subject.getPrincipals());
    }

}
